require 'rubygems/specification'
require 'rails/generators/named_base'
require 'rails/generators/resource_helpers'

module Quickstep
  module Generators
    class AdminControllerGenerator < Rails::Generators::NamedBase
      include Rails::Generators::ResourceHelpers

      source_root File.expand_path('../templates', __FILE__)

      check_class_collision suffix: "Controller"
      check_class_collision suffix: "Helper"

      class_option :orm, banner: "NAME", type: :string, required: true,
                   desc: "ORM to generate the controller for"

      class_option :html, type: :boolean, default: true,
                   desc: "Generate a scaffold with HTML output"

      class_option :prefix_name, banner: "admin", type: :string, default: "admin",
                   desc: "Define the prefix of controller"

      class_option :parent_controller, banner: "admin", type: :string, default: "Admin::Admin",
                   desc: "Define the parent controller"

      class_option :translated_model_name, type: :string

      class_option :enable_active, type: :boolean, default: false
      class_option :enable_recommend, type: :boolean, default: false
      class_option :simple_mode, type: :boolean, default: false

      argument :attributes, type: :array, default: [], banner: "field:type field:type"

      def initialize(args, *options) #:nodoc:
        super
      end

      hook_for :resource_route, in: :rails do |resource_route|
        invoke resource_route, [prefixed_class_name]
      end

      def create_controller_files
        template "controllers/railties/controller.rb.erb", File.join('app/controllers', prefix, class_path, "#{controller_file_name}_controller.rb")
      end


      hook_for :helper, in: :rails do |helper|
        invoke helper, [prefixed_controller_class_name]
      end

      def create_root_folder
        empty_directory File.join("app/views", prefix, controller_file_path)
      end

      def copy_view_files
        available_views.each do |view|
          filename = filename_with_extensions(view)
          if simple_mode? && view == 'index'
            template_path = "views/#{handler}_bootstrap/simple_index.html.erb.erb"
          else
            template_path = "views/#{handler}_bootstrap/#{filename}.erb"  
          end
          template template_path, File.join("app/views", prefix, controller_file_path, filename)
        end
      end

      protected
      def prefix
        options[:prefix_name]
      end

      def model_human_name
        options[:translated_model_name] && options[:translated_model_name].force_encoding(Encoding::ASCII_8BIT) || singular_name.capitalize
      end

      def class_path_array
        class_path_array = if @class_path.blank?
                             ""
                           else
                             @class_path.map {|part| ":#{part}"} .join(', ') + ','
                           end
        ":#{prefix}, #{class_path_array}"
      end

      def prefixed_new_path_array
        class_path_array = if @class_path.blank?
                            ","
                           else
                            @class_path.map {|part| ":#{part}"} .join(', ') + ','
                           end

        "[:new, :#{prefix}, #{class_path_array} :#{singular_name}]"
      end

      def prefixed_class_name
        "#{prefix.capitalize}::#{class_name}"
      end

      def prefixed_controller_class_name
        "#{prefix.capitalize}::#{controller_class_name}"
      end

      def parent_controller_class_name
        options[:parent_controller].split(/::|\//).map(&:capitalize).join("::")
      end

      def prefixed_route_url
        "/#{prefix}#{route_url}"
      end

      def prefixed_plain_model_url
        "#{prefix}_#{singular_table_name}"
      end

      def prefixed_index_helper
        "#{prefix}_#{index_helper}"
      end

      def name_field
        qualified_field('name', 'title')
      end

      def image_field
        qualified_field('avatar', 'image')
      end

      def qualified_field(*keywords)
        keywords.each do |keyword|
          return keyword if attributes_names.include?(keywords)
        end

        keywords.each do |keyword|
          attributes_names.each do |attr_name|
            return attr_name if attr_name.end_with?(keyword)
          end
        end

        nil
      end

      def simple_mode?
        options[:simple_mode]
      end

      def available_views

        views = if simple_mode?
          %w(index edit show new _form)
        else
          %w(index edit show new _form _list _detail _filter)
        end
      end

      def format
        :html
      end

      def handler
        'erb'
      end

      def filename_with_extensions(name)
        [name, format, handler].compact.join(".")
      end

      def active_enabled?
        options[:enable_active]
      end

      def recommend_enabled?
        options[:enable_recommend]
      end

      # Add a class collisions name to be checked on class initialization. You
      # can supply a hash with a :prefix or :suffix to be tested.
      #
      # ==== Examples
      #
      #   check_class_collision suffix: "Decorator"
      #
      # If the generator is invoked with class name Admin, it will check for
      # the presence of "AdminDecorator".
      #
      def self.check_class_collision(options={})
        define_method :check_class_collision do
          name = if self.respond_to?(:prefixed_controller_class_name) # for ScaffoldBase
            prefixed_controller_class_name
          elsif self.respond_to?(:prefixed_controller_class_name) # for ScaffoldBase
            controller_class_name
          else
            class_name
          end

          class_collisions "#{options[:prefix]}#{name}#{options[:suffix]}"
        end
      end

      def attributes_hash
        return if attributes_names.empty?

        attributes_names.map do |name|
          if %w(password password_confirmation).include?(name) && attributes.any?(&:password_digest?)
            "#{name}: 'secret'"
          else
            "#{name}: @#{singular_table_name}.#{name}"
          end
        end.sort.join(', ')
      end

      def attributes_list_with_timestamps
        attributes_list(attributes_names + %w(created_at updated_at))
      end

      def attributes_list(attributes = attributes_names)
        if self.attributes.any? {|attr| attr.name == 'password' && attr.type == :digest}
          attributes = attributes.reject {|name| %w(password password_confirmation).include? name}
        end

        attributes.map { |a| ":#{a}"} * ', '
      end

    end
  end
end
